#include "../include/Skill.hh"
#include "../include/Character.hh"
#include <iostream>
#include <algorithm>
#include <random>

#define COLOR_RED "\033[31m"
#define COLOR_RESET "\033[0m"

int calculateDamage(int baseSkillDamage, int attack, int defense, int armor, int penetration, float damageMultiplier, int critChance, int critDamage, bool& isCrit, int layer = 1) {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<float> dis(0.0f, 100.0f);

    int effectiveArmor = std::max(0, armor - penetration);
    int baseDamage = std::max(1, baseSkillDamage + attack - defense);
    float finalMultiplier = damageMultiplier * (1.0f + (layer - 1) * 0.2f); // Increase damage by 20% per layer

    isCrit = dis(gen) < critChance;
    if (isCrit) {
        finalMultiplier *= (1.0f + critDamage / 100.0f);
    }

    int finalDamage = static_cast<int>(baseDamage * (1.0f - effectiveArmor / 100.0f) * finalMultiplier);
    return std::max(1, finalDamage);
}

Skill create(SkillType type, int layer) {
    switch (type) {
        case NormalAttack:
            return Skill(
                "Normal Attack",
                "Performs a basic attack, dealing damage based on attack power.",
                [layer](Character& caster, Character& target) {
                    bool isCrit = false;
                    int damage = calculateDamage(
                        0, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier, caster.attributes.critChance,
                        caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    if (isCrit) {
                        std::cout << caster.name << " uses Normal Attack on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage!\n";
                    } else {
                        std::cout << caster.name << " uses Normal Attack on " << target.name << ", dealing "
                                  << damage << " damage!\n";
                    }
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case FireBall:
            return Skill(
                "Fireball Technique",
                "Launches a fireball, dealing base damage plus " + std::to_string(10 + layer * 5) + " points of magic damage.",
                [layer](Character& caster, Character& target) {
                    bool isCrit = false;
                    int damage = calculateDamage(
                        10 + layer * 5, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier, caster.attributes.critChance,
                        caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    if (isCrit) {
                        std::cout << caster.name << " uses Fireball Technique on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage!\n";
                    } else {
                        std::cout << caster.name << " uses Fireball Technique on " << target.name << ", dealing "
                                  << damage << " damage!\n";
                    }
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case Heal:
            return Skill(
                "Heal",
                "Restores " + std::to_string(30 + layer * 10) + " + (10% of current health) points of health to the caster and increases defense by " + std::to_string(5 + layer * 2) + " for 2 turns.",
                #pragma clang diagnostic push
                #pragma clang diagnostic ignored "-Wunused-lambda-capture"
                [layer](Character& caster, Character& /*target*/) {
                    int healing = (30 + layer * 10) + static_cast<int>(caster.attributes.health * 0.1f);
                    caster.heal(healing);
                    int defenseBonus = 5 + layer * 2;
                    caster.attributes.defense += defenseBonus;
                    auto& bonuses = const_cast<std::map<std::string, std::vector<Bonus>>&>(caster.getAttributeBonuses());
                    bonuses["defense"].push_back({"Heal", defenseBonus, true});
                    std::cout << caster.name << " uses Heal, restoring "
                              << healing << " health (current health: " << caster.attributes.health
                              << "/" << caster.maxHealth << ") and increasing defense by " << defenseBonus << " for 2 turns!\n";
                }
                #pragma clang diagnostic pop
            );

        case HealSuper:
            return Skill(
                "Haku Technique",
                "Restores " + std::to_string(30 + layer * 10) + " + (100% of current health) points of health to the caster and increases defense by " + std::to_string(100 + layer * 2) + " for 2 turns.",
                #pragma clang diagnostic push
                #pragma clang diagnostic ignored "-Wunused-lambda-capture"
                [layer](Character& caster, Character& /*target*/) {
                    int healing = (30 + layer * 10) + static_cast<int>(caster.attributes.health * 1.0f);
                    caster.heal(healing);
                    int defenseBonus = 100 + layer * 2;
                    caster.attributes.defense += defenseBonus;
                    auto& bonuses = const_cast<std::map<std::string, std::vector<Bonus>>&>(caster.getAttributeBonuses());
                    bonuses["defense"].push_back({"Haku Technique", defenseBonus, true});
                    std::cout << caster.name << " uses Haku Technique, restoring "
                              << healing << " health (current health: " << caster.attributes.health
                              << "/" << caster.maxHealth << ") and increasing defense by " << defenseBonus << " for 2 turns!\n";
                }
                #pragma clang diagnostic pop
            );

        case DevastatingStrike:
            return Skill(
                "Devastating Strike",
                "Deals high damage, ignoring 50% of armor, with " + std::to_string(1.5 + layer * 0.1) + "x damage multiplier, but consumes 33% of current health.",
                [layer](Character& caster, Character& target) {
                    bool isCrit = false;
                    int effectiveArmor = static_cast<int>(target.attributes.armor * 0.5);
                    int damage = calculateDamage(
                        15 + layer * 5, caster.attributes.attack, target.attributes.defense,
                        effectiveArmor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier * (1.5f + layer * 0.1f),
                        caster.attributes.critChance, caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    int healthCost = static_cast<int>(0.33 * caster.attributes.health);
                    caster.attributes.health = std::max(0, caster.attributes.health - healthCost);
                    if (isCrit) {
                        std::cout << caster.name << " uses Devastating Strike on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage! But loses " << healthCost << " health!\n";
                    } else {
                        std::cout << caster.name << " uses Devastating Strike on " << target.name << ", dealing "
                                  << damage << " damage! But loses " << healthCost << " health!\n";
                    }
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case ThunderStrike:
            return Skill(
                "Thunder Strike",
                "Unleashes a lightning attack, dealing high damage with a " + std::to_string(30 + layer * 5) + "% chance to stun the enemy.",
                [layer](Character& caster, Character& target) {
                    std::random_device rd;
                    std::mt19937 gen(rd());
                    std::uniform_real_distribution<float> dis(0.0f, 1.0f);
                    bool isCrit = false;
                    int damage = calculateDamage(
                        20 + layer * 5, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier * (1.2f + layer * 0.1f),
                        caster.attributes.critChance, caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    if (isCrit) {
                        std::cout << caster.name << " uses Thunder Strike on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage!\n";
                    } else {
                        std::cout << caster.name << " uses Thunder Strike on " << target.name << ", dealing "
                                  << damage << " damage!\n";
                    }
                    float stunChance = (30 + layer * 5) / 100.0f;
                    if (dis(gen) < stunChance && !target.isControlImmune()) {
                        target.isStunned = true;
                        std::cout << target.name << " is stunned and cannot act next turn!\n";
                    } else if (target.isControlImmune()) {
                        std::cout << target.name << " is immune to stun effects!\n";
                    }
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case ShadowBurst:
            return Skill(
                "Shadow Burst",
                "Releases shadow energy, dealing high damage and reducing the target's defense by " + std::to_string(5 + layer * 2) + " for 1 turn.",
                [layer](Character& caster, Character& target) {
                    bool isCrit = false;
                    int damage = calculateDamage(
                        20 + layer * 5, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier, caster.attributes.critChance,
                        caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    int defenseReduction = 5 + layer * 2;
                    if (isCrit) {
                        std::cout << caster.name << " uses Shadow Burst on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage and reducing defense by " << defenseReduction << " for 1 turn!\n";
                    } else {
                        std::cout << caster.name << " uses Shadow Burst on " << target.name << ", dealing "
                                  << damage << " damage and reducing defense by " << defenseReduction << " for 1 turn!\n";
                    }
                    target.attributes.defense = std::max(0, target.attributes.defense - defenseReduction);
                    auto& bonuses = const_cast<std::map<std::string, std::vector<Bonus>>&>(target.getAttributeBonuses());
                    bonuses["defense"].push_back({"Shadow Burst", -defenseReduction, true});
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case BloodAttack:
            return Skill(
                "Blood Attack",
                "Performs an attack, dealing damage based on attack power and restoring " + std::to_string(30 + layer * 5) + "% of the damage dealt as health.",
                [layer](Character& caster, Character& target) {
                    bool isCrit = false;
                    int damage = calculateDamage(
                        0, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier, caster.attributes.critChance,
                        caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    int healAmount = static_cast<int>((0.3 + layer * 0.05) * damage);
                    caster.heal(healAmount);
                    if (isCrit) {
                        std::cout << caster.name << " uses Blood Attack on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage! And restores " << healAmount << " health (current health: "
                                  << caster.attributes.health << "/" << caster.maxHealth << ")!\n";
                    } else {
                        std::cout << caster.name << " uses Blood Attack on " << target.name << ", dealing "
                                  << damage << " damage! And restores " << healAmount << " health (current health: "
                                  << caster.attributes.health << "/" << caster.maxHealth << ")!\n";
                    }
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case IronShield:
            return Skill(
                "Iron Shield",
                "Increases the caster's defense by " + std::to_string(10 + layer * 5) + " for 2 turns.",
                [layer](Character& caster, Character& /*target*/) {
                    int defenseBonus = 10 + layer * 5;
                    caster.attributes.defense += defenseBonus;
                    auto& bonuses = const_cast<std::map<std::string, std::vector<Bonus>>&>(caster.getAttributeBonuses());
                    bonuses["defense"].push_back({"Iron Shield", defenseBonus, true});
                    std::cout << caster.name << " uses Iron Shield, increasing defense by " << defenseBonus << " for 2 turns!\n";
                });

        case GoldenStrike:
            return Skill(
                "Golden Slash",
                "Deals high damage and increases the caster's critical chance by " + std::to_string(10 + layer * 5) + "% for 2 turns.",
                [layer](Character& caster, Character& target) {
                    bool isCrit = false;
                    int damage = calculateDamage(
                        15 + layer * 5, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier, caster.attributes.critChance,
                        caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    int critBonus = 10 + layer * 5;
                    caster.attributes.critChance += critBonus;
                    auto& bonuses = const_cast<std::map<std::string, std::vector<Bonus>>&>(caster.getAttributeBonuses());
                    bonuses["critChance"].push_back({"Golden Slash", critBonus, true});
                    if (isCrit) {
                        std::cout << caster.name << " uses Golden Slash on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage! And increases critical chance by " << critBonus << "% for 2 turns!\n";
                    } else {
                        std::cout << caster.name << " uses Golden Slash on " << target.name << ", dealing "
                                  << damage << " damage! And increases critical chance by " << critBonus << "% for 2 turns!\n";
                    }
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case OverloadPulse:
            return Skill(
                "Overload Pulse",
                "Deals damage and reduces the target's speed by " + std::to_string(5 + layer * 2) + " for 2 turns.",
                [layer](Character& caster, Character& target) {
                    bool isCrit = false;
                    int damage = calculateDamage(
                        10 + layer * 5, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier, caster.attributes.critChance,
                        caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    int speedReduction = 5 + layer * 2;
                    target.attributes.speed = std::max(0, target.attributes.speed - speedReduction);
                    auto& bonuses = const_cast<std::map<std::string, std::vector<Bonus>>&>(target.getAttributeBonuses());
                    bonuses["speed"].push_back({"Overload Pulse", -speedReduction, true});
                    if (isCrit) {
                        std::cout << caster.name << " uses Overload Pulse on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage! And reduces speed by " << speedReduction << " for 2 turns!\n";
                    } else {
                        std::cout << caster.name << " uses Overload Pulse on " << target.name << ", dealing "
                                  << damage << " damage! And reduces speed by " << speedReduction << " for 2 turns!\n";
                    }
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case ExplosiveBlast:
            return Skill(
                "Explosive Blast",
                "Deals massive area damage with a base value of " + std::to_string(20 + layer * 10) + ".",
                [layer](Character& caster, Character& target) {
                    bool isCrit = false;
                    int damage = calculateDamage(
                        20 + layer * 10, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier, caster.attributes.critChance,
                        caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    if (isCrit) {
                        std::cout << caster.name << " uses Explosive Blast on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage!\n";
                    } else {
                        std::cout << caster.name << " uses Explosive Blast on " << target.name << ", dealing "
                                  << damage << " damage!\n";
                    }
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case JuiceSplash:
            return Skill(
                "Juice Splash",
                "Deals damage and reduces the target's armor by " + std::to_string(10 + layer * 5) + " for 2 turns.",
                [layer](Character& caster, Character& target) {
                    bool isCrit = false;
                    int damage = calculateDamage(
                        15 + layer * 5, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier, caster.attributes.critChance,
                        caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    int armorReduction = 10 + layer * 5;
                    target.attributes.armor = std::max(0, target.attributes.armor - armorReduction);
                    auto& bonuses = const_cast<std::map<std::string, std::vector<Bonus>>&>(target.getAttributeBonuses());
                    bonuses["armor"].push_back({"Juice Splash", -armorReduction, true});
                    if (isCrit) {
                        std::cout << caster.name << " uses Juice Splash on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage! And reduces armor by " << armorReduction << " for 2 turns!\n";
                    } else {
                        std::cout << caster.name << " uses Juice Splash on " << target.name << ", dealing "
                                  << damage << " damage! And reduces armor by " << armorReduction << " for 2 turns!\n";
                    }
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case HellfireStorm:
            return Skill(
                "Hellfire Storm",
                "Unleashes a devastating firestorm, dealing " + std::to_string(30 + layer * 10) + " base damage and reducing the target's defense by " + std::to_string(10 + layer * 5) + " for 2 turns.",
                [layer](Character& caster, Character& target) {
                    bool isCrit = false;
                    int damage = calculateDamage(
                        30 + layer * 10, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier, caster.attributes.critChance,
                        caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    int defenseReduction = 10 + layer * 5;
                    target.attributes.defense = std::max(0, target.attributes.defense - defenseReduction);
                    auto& bonuses = const_cast<std::map<std::string, std::vector<Bonus>>&>(target.getAttributeBonuses());
                    bonuses["defense"].push_back({"Hellfire Storm", -defenseReduction, true});
                    if (isCrit) {
                        std::cout << caster.name << " uses Hellfire Storm on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage! And reduces defense by " << defenseReduction << " for 2 turns!\n";
                    } else {
                        std::cout << caster.name << " uses Hellfire Storm on " << target.name << ", dealing "
                                  << damage << " damage! And reduces defense by " << defenseReduction << " for 2 turns!\n";
                    }
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case ThunderBird:
            return Skill(
                "Thunder Bird",
                "Deals damage based on attack power with a 150% damage multiplier and a 50% chance to stun the target.",
                [layer](Character& caster, Character& target) {
                    std::random_device rd;
                    std::mt19937 gen(rd());
                    std::uniform_real_distribution<float> dis(0.0f, 100.0f);
                    bool isCrit = false;
                    int damage = calculateDamage(
                        0, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier * 1.5f,
                        caster.attributes.critChance, caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    if (isCrit) {
                        std::cout << caster.name << " uses Thunder Bird on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage!\n";
                    } else {
                        std::cout << caster.name << " uses Thunder Bird on " << target.name << ", dealing "
                                  << damage << " damage!\n";
                    }
                    if (dis(gen) < 50.0f && !target.isControlImmune()) {
                        target.isStunned = true;
                        std::cout << target.name << " is stunned and cannot act next turn!\n";
                    } else if (target.isControlImmune()) {
                        std::cout << target.name << " is immune to stun effects!\n";
                    }
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case GreatFireball:
            return Skill(
                "Great Fireball",
                "Deals damage based on attack power with a 50% damage multiplier and inflicts a burn effect, causing 30% of the target's max health as damage per turn for 3 turns.",
                [layer](Character& caster, Character& target) {
                    bool isCrit = false;
                    int damage = calculateDamage(
                        0, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier * 0.5f,
                        caster.attributes.critChance, caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    if (isCrit) {
                        std::cout << caster.name << " uses Great Fireball on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage!\n";
                    } else {
                        std::cout << caster.name << " uses Great Fireball on " << target.name << ", dealing "
                                  << damage << " damage!\n";
                    }
                    int burnDamage = static_cast<int>(target.maxHealth * 0.3f);
                    auto& bonuses = const_cast<std::map<std::string, std::vector<Bonus>>&>(target.getAttributeBonuses());
                    bonuses["health"].push_back({"Great Fireball-Burn", -burnDamage, true});
                    std::cout << target.name << " is afflicted with a burn effect, losing "
                              << burnDamage << " health per turn for the next 3 turns!\n";
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case HundredHeal:
            return Skill(
                "Hundred Heal",
                "Restores (50 + 50% of max health) points of health and heals 10% of max health per turn for the next 3 turns.",
                [layer](Character& caster, Character& /*target*/) {
                    int initialHealing = 50 + static_cast<int>(caster.maxHealth * 0.5f);
                    caster.heal(initialHealing);
                    int healAmount = static_cast<int>(caster.maxHealth * 0.1f);
                    auto& bonuses = const_cast<std::map<std::string, std::vector<Bonus>>&>(caster.getAttributeBonuses());
                    bonuses["health"].push_back({"Hundred Heal-Continuous Heal", healAmount, true});
                    std::cout << caster.name << " uses Hundred Heal, restoring "
                              << initialHealing << " health (current health: " << caster.attributes.health
                              << "/" << caster.maxHealth << ") and will restore "
                              << healAmount << " health per turn for the next 3 turns!\n";
                });

        case AssaultPierce:
            return Skill(
                "Assault Thrust",
                "Deals damage based on attack power with a 250% damage multiplier and reduces the target's armor by " + std::to_string(25 + layer * 5) + " + 30% of the target's armor value.",
                [layer](Character& caster, Character& target) {
                    bool isCrit = false;
                    int damage = calculateDamage(
                        0, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        caster.attributes.damageMultiplier * 2.5f,
                        caster.attributes.critChance, caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    int armorReduction = 25 + static_cast<int>(target.attributes.armor * 0.3f);
                    target.attributes.armor = std::max(0, target.attributes.armor - armorReduction);
                    auto& bonuses = const_cast<std::map<std::string, std::vector<Bonus>>&>(target.getAttributeBonuses());
                    bonuses["armor"].push_back({"Assault Thrust", -armorReduction, true});
                    if (isCrit) {
                        std::cout << caster.name << " uses Assault Thrust on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage! And reduces armor by " << armorReduction << " for 2 turns!\n";
                    } else {
                        std::cout << caster.name << " uses Assault Thrust on " << target.name << ", dealing "
                                  << damage << " damage! And reduces armor by " << armorReduction << " for 2 turns!\n";
                    }
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case BleedingWound:
            return Skill(
                "Endless Bleeding",
                "Deals damage based on attack power with a 100% damage multiplier, inflicts a bleeding effect causing 20% of the target's max health as damage per turn for 3 turns, disables all healing skills, and has a 1% chance to deal 10x damage.",
                [layer](Character& caster, Character& target) {
                    std::random_device rd;
                    std::mt19937 gen(rd());
                    std::uniform_real_distribution<float> dis(0.0f, 100.0f);
                    bool isCrit = false;
                    float damageMultiplier = caster.attributes.damageMultiplier;
                    if (dis(gen) < 1.0f) {
                        damageMultiplier *= 10.0f;
                        std::cout << caster.name << " triggers Endless Bleeding's 10x damage effect!\n";
                    }
                    int damage = calculateDamage(
                        0, caster.attributes.attack, target.attributes.defense,
                        target.attributes.armor, caster.attributes.penetration,
                        damageMultiplier,
                        caster.attributes.critChance, caster.attributes.critDamage, isCrit, layer
                    );
                    target.attributes.health = std::max(0, target.attributes.health - damage);
                    int bleedDamage = static_cast<int>(target.maxHealth * 0.2f);
                    auto& bonuses = const_cast<std::map<std::string, std::vector<Bonus>>&>(target.getAttributeBonuses());
                    bonuses["health"].push_back({"Endless Bleeding-Bleed", -bleedDamage, true});
                    target.isHealingDisabled = true;
                    if (isCrit) {
                        std::cout << caster.name << " uses Endless Bleeding on " << target.name << ", triggering a critical hit, dealing "
                                  << COLOR_RED << damage << COLOR_RESET << " damage! And inflicts a bleeding effect, losing "
                                  << bleedDamage << " health per turn for 3 turns, with healing effects disabled!\n";
                    } else {
                        std::cout << caster.name << " uses Endless Bleeding on " << target.name << ", dealing "
                                  << damage << " damage! And inflicts a bleeding effect, losing "
                                  << bleedDamage << " health per turn for 3 turns, with healing effects disabled!\n";
                    }
                    if (target.attributes.health <= 0 && target.handleFatalDamage()) {
                        target.attributes.health = 1;
                    }
                });

        case SoulInfiltration:
            return Skill(
                "Soul Infiltration",
                "Increases critical damage by 200% and guarantees a critical hit on the next turn, while restoring 50% of max health.",
                #pragma clang diagnostic push
                #pragma clang diagnostic ignored "-Wunused-lambda-capture"
                [layer](Character& caster, Character& /*target*/) {
                    int critChanceBonus = 100;
                    int critDamageBonus = 200;
                    int healing = static_cast<int>(caster.maxHealth * 0.5f);
                    caster.heal(healing);
                    auto& bonuses = const_cast<std::map<std::string, std::vector<Bonus>>&>(caster.getAttributeBonuses());
                    bonuses["critChance"].push_back({"Soul Infiltration", critChanceBonus, true});
                    bonuses["critDamage"].push_back({"Soul Infiltration", critDamageBonus, true});
                    std::cout << caster.name << " uses Soul Infiltration, increasing critical chance by " << critChanceBonus << "% and critical damage by "
                              << critDamageBonus << "% and restoring " << healing << " health (current health: "
                              << caster.attributes.health << "/" << caster.maxHealth << ")!\n";
                }
                #pragma clang diagnostic pop
            );

        default:
            throw std::invalid_argument("Unknown SkillType: " + std::to_string(static_cast<int>(type)));
    }
}

Skill::Skill(const std::string& name, const std::string& desc,
             const std::function<void(Character&, Character&)>& eff)
    : name(name), description(desc), effect(eff) {}

void Skill::use(Character& caster, Character& target) const {
    if (effect) {
        effect(caster, target);
    } else {
        std::cout << name << " has no effect!\n";
    }
}